﻿using System;
using System.Globalization;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Threading;

using Microsoft.Practices.Unity;
using Zuehlke.Blueprint.Quickstart.Architecture.Domain.Services;
using Zuehlke.Blueprint.Quickstart.Architecture.Domain.Services.Interfaces;
using Zuehlke.Blueprint.Quickstart.Architecture.Launcher.Extensions;
using Zuehlke.Blueprint.Quickstart.Architecture.Presentation.Services.BackgroundTasks;
using Zuehlke.Blueprint.Quickstart.Architecture.Presentation.Services.Customers;
using Zuehlke.Blueprint.Quickstart.Architecture.Presentation.Services.Interfaces.BackgroundTasks;
using Zuehlke.Blueprint.Quickstart.Architecture.Presentation.Services.Interfaces.Customers;
using Zuehlke.Blueprint.Quickstart.Architecture.Presentation.UserInterface;
using Zuehlke.Blueprint.Quickstart.Architecture.Presentation.UserInterface.Localization;

namespace Zuehlke.Blueprint.Quickstart.Architecture.Launcher
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App
    {
        #region Private Members

        private readonly IUnityContainer _container;

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="App"/> class.
        /// </summary>
        public App()
        {
            _container = CreateContainer();
        }

        #endregion

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            InitializeExceptionHandling();

            Thread.CurrentThread.CurrentUICulture = new CultureInfo("de");
            InitializeTranslation();
            
            MainWindow = _container.Resolve<Shell>();
            MainWindow.Show();
        }

        private void InitializeExceptionHandling()
        {
            Dispatcher.CurrentDispatcher.UnhandledException += OnUnhandledUiException;
            AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
        }

        private void OnUnhandledUiException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            var exceptionOutput = new StringBuilder("Exception on UI thread occurred:");
            exceptionOutput.AppendLine(e.Exception.Message);
            exceptionOutput.AppendLine(e.Exception.StackTrace);

            Console.WriteLine(exceptionOutput);

            // Set handled, otherwise the application cannot continue!
            e.Handled = true;
        }

        private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            var exceptionOutput = new StringBuilder("Exception on background thread occurred:");
            exceptionOutput.AppendLine(((Exception)e.ExceptionObject).Message);
            exceptionOutput.AppendLine(((Exception)e.ExceptionObject).StackTrace);

            Console.WriteLine(exceptionOutput);

            // We cannot prevent the application from crashing but we were able to log the exception before crash.
        }

        private static void InitializeTranslation()
        {
            TranslationManager.Initialize(
                "Zuehlke.Blueprint.Quickstart.Architecture.Presentation.Localization.Resources",
                Assembly.Load("Zuehlke.Blueprint.Quickstart.Architecture.Presentation.Localization"));
        } 

        protected override void OnExit(ExitEventArgs e)
        {
            base.OnExit(e);

            // Clean-up
            _container.Dispose();
        }

        private static IUnityContainer CreateContainer()
        {
            var container = new UnityContainer();

            container.RegisterSingleton<ICustomerService, CustomerService>();
            container.RegisterSingleton<ICustomerPersistencyService, CustomerPersistencyService>();
            container.RegisterSingleton<IBackgroundTasksService, BackgroundTasksService>();

            return container;
        }
    }
}
